<template>
  <div ref="contextMenuRoot" 挂载点>
    <Teleport to="body">
      <div
        v-show="show"
        :style="{
          position: 'absolute',
          left: `${position.x}px`,
          top: `${position.y}px`,
          zIndex: zIndex ?? 10000,
        }">
        <div ref="el">
          <slot></slot>
        </div>
      </div>
    </Teleport>
  </div>
</template>

<script setup lang="ts">
import { onClickOutside } from '@vueuse/core';
import { MathPoint } from '~/models/Math/MathPoint';

const show = ref(false)
const pinned = ref(false)
const position = ref(new MathPoint())
const contextMenuRoot = ref(null as HTMLElement | null)
const parent = ref(null as HTMLElement | null)

const emits = defineEmits<{
  (e: 'onPop', event: MouseEvent): void,
  (e: 'onHide', event: void): void,
  (e: 'onMove', event: MouseEvent): void,
}>()

const props = defineProps<{
  outsideIgnore?: string[]
  zIndex?: number
}>()

function pop(ev: MouseEvent) {
  if (!show.value) {
    show.value = true
    position.value = new MathPoint(ev.clientX, ev.clientY)
    emits('onPop', ev)
  }
}
function move(ev: MouseEvent) {
  if (show.value) {
    position.value = new MathPoint(ev.clientX, ev.clientY)
    emits('onMove', ev)
  }
}
function hide() {
  if (show.value) {
    show.value = false
    emits('onHide')
    // throw new Error('BaseContextMenu: hide')
  }
}

function onParentContext(ev: MouseEvent) {

  // 禁用原本的右键菜单
  ev.preventDefault()

  // 防止弹出多个菜单
  ev.stopPropagation()

  if (show.value) {
    move(ev)
  }
  else {
    pop(ev)
  }
}


const el = ref(null as any)
onClickOutside(el, onClickOut, {
  ignore: props.outsideIgnore
})
function onClickOut(ev: MouseEvent) {
  // 未渲染时，不进行隐藏相关的事件传递
  if (show.value && !pinned.value) {
    hide()
  }
}

defineExpose({
  show,
  pinned,
  pop,
  hide,
})

onMounted(() => {
  
  parent.value = contextMenuRoot.value?.parentNode as HTMLElement  
  // 显示
  parent.value.addEventListener('contextmenu', onParentContext)
})

onUnmounted(() => {
  if (parent.value !== null) {
    parent.value.removeEventListener('contextmenu', onParentContext)
  }
  else {
    console.error('BaseContextMenu: parent丢失!');
  }
})
</script>